package dominioDoProblema;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import dominioDaSolucao.Quadrado;

public class Tetramino  {
	
	protected int orientacao;
	protected int tipo;
	protected Quadrado quadradoReferencia;
	protected List<Quadrado> quadrados;
	protected MatrizDeQuadrados matriz; 
	protected String nomeJogador;
	protected int cor;

	public Tetramino(Quadrado quadradoReferencia, MatrizDeQuadrados matriz,
			String nomeJogador, int cor) {
		this.quadradoReferencia = quadradoReferencia;
		this.matriz = matriz;
		this.nomeJogador = nomeJogador;
		this.cor = cor;
		gerarAleatorio();
	}

	public Tetramino(Quadrado quadradoReferencia, MatrizDeQuadrados matriz,
			String nomeJogador, int tipo, int orientacao, int cor) {

		this.quadradoReferencia = quadradoReferencia;
		this.matriz = matriz;
		this.nomeJogador = nomeJogador;
		this.cor = cor;
		this.orientacao = orientacao;
		this.tipo = tipo;
		quadrados = gerarReferencias(quadradoReferencia, orientacao);
	}

	public void redesenharQuadrados(){
		redesenharQuadrados(quadradoReferencia, orientacao);
	}
	
	public void redesenharQuadrados(Quadrado quadradoReferencia, int orientacao) {
		this.quadrados = gerarReferencias(quadradoReferencia, orientacao);
		this.orientacao = orientacao;

		quadradoReferencia.setOcupado(true);
 		int x = quadradoReferencia.getXRef();
		int y = quadradoReferencia.getYRef();
		this.matriz.preencher(x, y, nomeJogador, cor, true);
 		for (Quadrado quadrado : quadrados) {
 			quadrado.setOcupado(true);
  			x = quadrado.getXRef();
			y = quadrado.getYRef();
			this.matriz.preencher(x, y, nomeJogador, cor, true);
		}
 	}

	public void girar() {
		int orient = getOrientacao();
		orient--;
		if (orient < 0) {
			orient = 3;
		}
		int x = quadradoReferencia.getXRef();
		int y = quadradoReferencia.getYRef();
		this.matriz.setOcupado(x, y, false);
		boolean posicaoValida = ((Tabuleiro) matriz).verificaSePosicaoEhValida(
				quadradoReferencia, this, orient);
		if (posicaoValida) {
			redesenharQuadrados(quadradoReferencia, orient);
		} else {
			this.matriz.setOcupado(x, y, true);
		}
	}

	public void deslocarParaDireita() {
		int x = quadradoReferencia.getXRef();
		int y = quadradoReferencia.getYRef();
		Quadrado quadrado = matriz.getQuadrado(x, y + 1);
		this.matriz.setOcupado(x, y, false);
		boolean posicaoValida;
		posicaoValida = ((Tabuleiro) matriz)
				.verificaPosicaoValidaQuadradoReferencia(x, y, this, 1);
		if (posicaoValida) {
			posicaoValida = ((Tabuleiro) matriz).verificaSePosicaoEhValida(
					quadrado, this, orientacao);
			if (posicaoValida) {
				setQuadradoReferencia(quadrado);
				redesenharQuadrados(quadradoReferencia, orientacao);
			} else {
				this.matriz.setOcupado(x, y, true);
			}
		} else {
			this.matriz.setOcupado(x, y, true);
		}
	}

	public void deslocarParaEsquerda() {
		int x = quadradoReferencia.getXRef();
		int y = quadradoReferencia.getYRef();
		Quadrado quadrado = matriz.getQuadrado(x, y - 1);
		this.matriz.setOcupado(x, y, false);
		boolean posicaoValida = false;
		posicaoValida = ((Tabuleiro) matriz)
				.verificaPosicaoValidaQuadradoReferencia(x, y, this, 2);
		if (posicaoValida) {
			posicaoValida = ((Tabuleiro) matriz).verificaSePosicaoEhValida(
					quadrado, this, orientacao);
			if (posicaoValida) {
				setQuadradoReferencia(quadrado);
				redesenharQuadrados(quadradoReferencia, orientacao);
			} else {
				this.matriz.setOcupado(x, y, true);
			}
		} else {
			this.matriz.setOcupado(x, y, true);
		}
	}

	public boolean acelerarQueda() {
		boolean emQueda = true;
		int x = quadradoReferencia.getXRef();
		int y = quadradoReferencia.getYRef();
		Quadrado quadrado = matriz.getQuadrado(x + 1, y);
		quadradoReferencia.setOcupado(false);
		boolean posicaoValida;
 		posicaoValida = ((Tabuleiro) matriz)
				.verificaPosicaoValidaQuadradoReferencia(x, y, this, 3);
		if (posicaoValida) {
 			posicaoValida = ((Tabuleiro) matriz).verificaSePosicaoEhValida(
					quadrado, this, orientacao);
 			if (posicaoValida) {
 				setQuadradoReferencia(quadrado);
 				redesenharQuadrados(quadradoReferencia, orientacao);
 			} else {
 				this.matriz.preencher(x, y, nomeJogador, cor, true);
 				emQueda = false;
 			}
 			
		} else {
			this.matriz.preencher(x, y, nomeJogador, cor, true);
				emQueda = false;
		}
		return emQueda;
	}

	public void apagarAntigos() {
 		if (quadrados != null) {

			int x, y;
   			for (Quadrado quadrado : quadrados) {
  				x = quadrado.getXRef();
 				y = quadrado.getYRef();
 				this.matriz.preencher(x, y, null, -1, false);
			}
			x = quadradoReferencia.getXRef();
			y = quadradoReferencia.getYRef();
			this.matriz.preencher(x, y, null, -1, false);
		}
	}

	public void gerarAleatorio() {
		Random rn = new Random();
		int randonN = rn.nextInt();
		if (randonN < 0) {
			randonN = randonN * (-1);
		}
		int randomNumOrientacao = randonN % 3;

		randonN = rn.nextInt();
		if (randonN < 0) {
			randonN = randonN * (-1);
		}
		int randomNumtipo = randonN % 7;
		this.orientacao = randomNumOrientacao;
		this.tipo = randomNumtipo;
				
		atualizarQuadradoReferencia();
		
		quadrados = gerarReferencias(quadradoReferencia, orientacao);
 		redesenharQuadrados(quadradoReferencia, orientacao);
	}

	public void atualizarQuadradoReferencia(){
 		if (matriz instanceof Tabuleiro){
			switch (tipo) {
			case 0:				
				if (orientacao == 0){
					quadradoReferencia = this.matriz.getQuadrado(0, 4);
				} else {
					quadradoReferencia = this.matriz.getQuadrado(1, 4);
				}
				break;
			case 1:				
					quadradoReferencia = this.matriz.getQuadrado(0, 4);				
				break;
			case 2:
				if (orientacao == 0 || orientacao == 2){
					quadradoReferencia = this.matriz.getQuadrado(0, 4);
				} else {
					quadradoReferencia = this.matriz.getQuadrado(1, 4);
				}
				break;
			case 3:
				quadradoReferencia = this.matriz.getQuadrado(1, 4);
				break;
			case 4: 
				quadradoReferencia = this.matriz.getQuadrado(1, 4);
				break;
			case 5:
				if (orientacao == 0){
					quadradoReferencia = this.matriz.getQuadrado(0, 4);
				} else {
					quadradoReferencia = this.matriz.getQuadrado(1, 4);
				}
				break;
			case 6:
				if (orientacao == 3){
					quadradoReferencia = this.matriz.getQuadrado(0, 4);
				} else {
					quadradoReferencia = this.matriz.getQuadrado(1, 4);
				}
				break;
			default:
				break;
			}
			}
	}
	
	public List<Quadrado> gerarReferencias(Quadrado quadradoReferencia,
			int orientacao) {
  		int x = quadradoReferencia.getXRef();
  		int y = quadradoReferencia.getYRef();
 		LinkedList<Quadrado> quadrados = new LinkedList<Quadrado>();
  		switch (tipo) {
		case 0:
			if (orientacao == 0) {
				quadrados.add(matriz.getQuadrado(x, y + 1));
				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x + 1, y));
			} else if (orientacao == 1) {
				quadrados.add(matriz.getQuadrado(x + 1, y));
				quadrados.add(matriz.getQuadrado(x - 1, y));
				quadrados.add(matriz.getQuadrado(x, y + 1));
			} else if (orientacao == 2) {
				quadrados.add(matriz.getQuadrado(x, y + 1));
				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x - 1, y));
			} else if (orientacao == 3) {
				quadrados.add(matriz.getQuadrado(x + 1, y));
				quadrados.add(matriz.getQuadrado(x - 1, y));
				quadrados.add(matriz.getQuadrado(x, y - 1));
			}
			break;
		case 1:
			quadrados.add(matriz.getQuadrado(x + 1, y));
 			quadrados.add(matriz.getQuadrado(x, y + 1));
			quadrados.add(matriz.getQuadrado(x + 1, y + 1));
			break;
		case 2:
			if (orientacao == 0 || orientacao == 2) {
				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x, y + 1));
				quadrados.add(matriz.getQuadrado(x, y + 2));
			} else if (orientacao == 1 || orientacao == 3) {
				quadrados.add(matriz.getQuadrado(x - 1, y));
				quadrados.add(matriz.getQuadrado(x + 1, y));
				quadrados.add(matriz.getQuadrado(x + 2, y));
			}
			break;
		case 3:
			if (orientacao == 0 || orientacao == 2) {
				quadrados.add(matriz.getQuadrado(x + 1, y));
				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x - 1, y - 1));
 			} else if (orientacao == 1 || orientacao == 3) {
  				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x - 1, y));
				quadrados.add(matriz.getQuadrado(x - 1, y + 1));
			}
			break;
		case 4:
			if (orientacao == 0 || orientacao == 2) {
				quadrados.add(matriz.getQuadrado(x - 1, y));
				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x + 1, y - 1));
			} else if (orientacao == 1 || orientacao == 3) {
				quadrados.add(matriz.getQuadrado(x - 1, y));
				quadrados.add(matriz.getQuadrado(x, y + 1));
				quadrados.add(matriz.getQuadrado(x - 1, y - 1));
			}
			break;
		case 5:
			if (orientacao == 0) {
				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x, y + 1));
				quadrados.add(matriz.getQuadrado(x + 1, y - 1));
			} else if (orientacao == 1) {
				quadrados.add(matriz.getQuadrado(x - 1, y));
				quadrados.add(matriz.getQuadrado(x + 1, y));
				quadrados.add(matriz.getQuadrado(x + 1, y + 1));
			} else if (orientacao == 2) {
				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x, y + 1));
				quadrados.add(matriz.getQuadrado(x - 1, y + 1));
			} else if (orientacao == 3) {
				quadrados.add(matriz.getQuadrado(x + 1, y));
				quadrados.add(matriz.getQuadrado(x - 1, y));
				quadrados.add(matriz.getQuadrado(x - 1, y - 1));
			}
			break;
		case 6:
			if (orientacao == 0) {
				quadrados.add(matriz.getQuadrado(x + 1, y));
				quadrados.add(matriz.getQuadrado(x - 1, y));
				quadrados.add(matriz.getQuadrado(x - 1, y + 1));
 			} else if (orientacao == 1) {
				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x, y + 1));
				quadrados.add(matriz.getQuadrado(x - 1, y - 1));
 			} else if (orientacao == 2) {
 				quadrados.add(matriz.getQuadrado(x + 1, y));
 				quadrados.add(matriz.getQuadrado(x - 1, y));
 				quadrados.add(matriz.getQuadrado(x + 1, y - 1));
 			} else if (orientacao == 3) {
				quadrados.add(matriz.getQuadrado(x, y - 1));
				quadrados.add(matriz.getQuadrado(x, y + 1));
				quadrados.add(matriz.getQuadrado(x + 1, y + 1));
			}
			break;
		}
   		boolean zerarQuadrados = false;
   		for (Quadrado quad : quadrados) {
 			if (quad.getXRef() == -1) {
				zerarQuadrados = true;
				break;
			}
		}
 		if (zerarQuadrados) {
			quadrados = new LinkedList<Quadrado>();
		}
		return quadrados;
	}

	public Quadrado getQuadradoReferencia() {
		return this.quadradoReferencia;
	}

	public void setQuadradoReferencia(Quadrado quadradoReferencia) {
		this.quadradoReferencia = quadradoReferencia;
	}

	public List<Quadrado> getQuadrados() {
		return quadrados;
	}

	public void setMatriz(MatrizDeQuadrados matriz) {
		this.matriz = matriz;
		atualizarQuadradoReferencia();
	}

	public int getOrientacao() {
		return orientacao;
	}

	public int getTipo() {
		return tipo;
	}

	public String getNomeJogador() {
		return nomeJogador;
	}

	public int getXRef() {
		return quadradoReferencia.getXRef();
	}

	public int getYRef() {
		return quadradoReferencia.getYRef();
	}

	public int getCor() {
		return cor;
	}

}